package com.dfe.backend.common.sax;

import cn.hutool.core.bean.BeanUtil;
import com.dfe.backend.common.sax.spd.SpdData;
import com.dfe.backend.common.sax.spd.substation.Bay;
import com.dfe.backend.common.sax.spd.substation.Region;
import com.dfe.backend.common.sax.spd.substation.Substation;
import com.dfe.backend.common.sax.spd.substation.bay.Cable;
import com.dfe.backend.common.sax.spd.substation.bay.DeviceRef;
import com.dfe.backend.common.sax.spd.substation.region.Core;
import com.dfe.backend.common.sax.spd.substation.region.Cubicle;
import com.dfe.backend.common.sax.spd.substation.region.device.*;
import com.dfe.backend.common.sax.spd.substation.region.function.FunctionArea;
import com.dfe.backend.common.sax.spd.substation.region.function.FunctionGroup;
import com.dfe.backend.common.sax.spd.substation.region.function.Interface;
import com.dfe.backend.common.sax.spd.substation.region.function.Point;
import com.dfe.backend.common.sax.spd.templates.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 【描述】：
 *
 * @author LiChang
 * @since 2025-7-28 15:07
 */
@Slf4j
public class SpdServiceHandler extends DefaultHandler {

    public SpdData spdData = new SpdData();

    // 分析用的集合
    public Map<String, Cubicle> cubicleMap = new HashMap<>();
    public Map<String, Device> deviceMap = new HashMap<>();

    private List<PartTemplate> partTemplateList;
    private PartTemplate partTemplate;
    private List<ComponentTemplate> componentTemplateList;
    private List<InPartTemplate> inPartTemplateList;
    private List<PinTemplate> pinTemplateList;
    private List<InCoreTemplate> inCoreTemplateList;

    // 判断是否在InPartTemplate处理中
    private boolean isInPartTemplateFlag = false;
    private InPartTemplate inPartTemplate;
    private List<ComponentTemplate> inPartComponentTemplateList;
    private ComponentTemplate componentTemplate;
    private List<ComponentPinTemplate> componentPinTemplateList;

    // 厂站部分
    private Substation substation;
    private List<Region> regionList;
    private List<Bay> bayList;

    // Region部分
    private boolean isCubicleFlag = false;
    private Region region;
    private List<Cubicle> cubicleList;
    private Cubicle cubicle;
    private List<FunctionArea> functionAreaList;
    private List<Device> deviceList;
    private List<Core> coreList;

    // FunctionArea部分
    private FunctionArea functionArea;
    private List<FunctionGroup> functionGroupList;
    private FunctionGroup functionGroup;
    private List<Interface> interfaceList;
    private Interface interfaceOne;
    private List<Point> pointList;

    // Device部分，判定优先级：InDevice > SubDevice > Device
    private boolean isSubDeviceFlag = false;
    private boolean isInDeviceFlag = false;
    private Device device;
    private List<SubDevice> subDeviceList;
    private SubDevice subDevice;
    private List<InDevice> inDeviceList;
    private InDevice inDevice;
    private List<Component> componentList;
    private Component component;
    private List<ComponentPin> componentPinList;
    private List<InCore> inCoreList;
    private List<Pin> pinList;

    // SubDevice部分
    private List<InDevice> subInDeviceList;
    private InDevice subInDevice;
    private List<Component> subComponentList;
    private Component subComponent;
    private List<ComponentPin> subComponentPinList;
    private List<InCore> subInCoreList;
    private List<Pin> subPinList;

    // InDevice部分
    private List<Component> inDeviceComponentList;
    private Component inDeviceComponent;
    private List<ComponentPin> inDeviceComponentPinList;

    // Bay部分
    private Bay bay;
    private List<Cable> cableList;
    private Cable cable;
    private List<Core> cableCoreList;
    private List<DeviceRef> deviceRefList;

    /**
     * Receive notification of the start of an element.
     *
     * <p>By default, do nothing.  Application writers may override this
     * method in a subclass to take specific actions at the start of
     * each element (such as allocating a new tree node or writing
     * output to a file).</p>
     *
     * @param uri        The Namespace URI, or the empty string if the
     *                   element has no Namespace URI or if Namespace
     *                   processing is not being performed.
     * @param localName  The local name (without prefix), or the
     *                   empty string if Namespace processing is not being
     *                   performed.
     * @param qName      The qualified name (with prefix), or the
     *                   empty string if qualified names are not available.
     * @param attributes The attributes attached to the element.  If
     *                   there are no attributes, it shall be an empty
     *                   Attributes object.
     * @throws SAXException Any SAX exception, possibly
     *                      wrapping another exception.
     * @see ContentHandler#startElement
     */
    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
        switch (qName) {
            case "SPD":
                spdData = new SpdData();
                break;
            case "PartTemplates":
                partTemplateList = new ArrayList<>();
                break;
            case "PartTemplate":
                partTemplate = new PartTemplate();
                partTemplate.setName(attributes.getValue("name"));
                partTemplate.setType(attributes.getValue("type"));
                partTemplate.setDesc(attributes.getValue("desc"));
                partTemplate.setManufacturer(attributes.getValue("manufacturer"));
                partTemplate.setClassName(attributes.getValue("class"));
                // 初始化列表细节
                componentTemplateList = new ArrayList<>();
                inPartTemplateList = new ArrayList<>();
                pinTemplateList = new ArrayList<>();
                inCoreTemplateList = new ArrayList<>();
                break;
            case "ComponentTemplate":
                componentTemplate = new ComponentTemplate();
                componentTemplate.setName(attributes.getValue("name"));
                componentTemplate.setDesc(attributes.getValue("desc"));
                componentTemplate.setGroup(attributes.getValue("group"));
                componentTemplate.setType(attributes.getValue("type"));
                // 初始化列表细节
                componentPinTemplateList = new ArrayList<>();
                break;
            case "ComponentPinTemplate":
                ComponentPinTemplate componentPinTemplate = new ComponentPinTemplate();
                componentPinTemplate.setPinIndex(attributes.getValue("pinIndex"));
                componentPinTemplate.setPinDesc(attributes.getValue("pinDesc"));
                // 添加组件模板
                componentPinTemplateList.add(componentPinTemplate);
                break;
            case "InPartTemplate":
                // 更改InPartTemplate状态
                isInPartTemplateFlag = true;
                inPartTemplate = new InPartTemplate();
                inPartTemplate.setName(attributes.getValue("name"));
                inPartTemplate.setDesc(attributes.getValue("desc"));
                inPartTemplate.setType(attributes.getValue("type"));
                inPartTemplate.setManufacturer(attributes.getValue("manufacturer"));
                inPartTemplate.setClassName(attributes.getValue("class"));
                // 初始化列表细节
                inPartComponentTemplateList = new ArrayList<>();
                break;
            case "PinTemplate":
                PinTemplate pinTemplate = new PinTemplate();
                pinTemplate.setName(attributes.getValue("name"));
                pinTemplate.setDesc(attributes.getValue("desc"));
                pinTemplate.setType(attributes.getValue("type"));
                pinTemplate.setSide(attributes.getValue("side"));
                pinTemplateList.add(pinTemplate);
                break;
            case "InCoreTemplate":
                InCoreTemplate inCoreTemplate = new InCoreTemplate();
                inCoreTemplate.setName(attributes.getValue("name"));
                inCoreTemplate.setDesc(attributes.getValue("desc"));
                inCoreTemplate.setStartInPart(attributes.getValue("startInPart"));
                inCoreTemplate.setStartComponent(attributes.getValue("startComponent"));
                inCoreTemplate.setStartPinIndex(attributes.getValue("startPinIndex"));
                inCoreTemplate.setEndInPart(attributes.getValue("endInPart"));
                inCoreTemplate.setEndComponent(attributes.getValue("endComponent"));
                inCoreTemplate.setEndPinIndex(attributes.getValue("endPinIndex"));
                inCoreTemplateList.add(inCoreTemplate);
                break;
            case "Substation":
                substation = new Substation();
                substation.setName(attributes.getValue("name"));
                substation.setDesc(attributes.getValue("desc"));
                substation.setGridName(attributes.getValue("gridName"));
                substation.setAreaName(attributes.getValue("areaName"));
                substation.setVoltage(attributes.getValue("voltage"));
                // 初始化列表细节
                regionList = new ArrayList<>();
                bayList = new ArrayList<>();
                break;
            case "Region":
                region = new Region();
                region.setName(attributes.getValue("name"));
                region.setDesc(attributes.getValue("desc"));
                region.setObjectId(attributes.getValue("objectId"));
                region.setArea(attributes.getValue("area"));
                // 初始化列表细节
                cubicleList = new ArrayList<>();
                break;
            case "Cubicle":
                isCubicleFlag = true;
                cubicle = new Cubicle();
                cubicle.setName(attributes.getValue("name"));
                cubicle.setDesc(attributes.getValue("desc"));
                cubicle.setClassName(attributes.getValue("class"));
                cubicle.setType(attributes.getValue("type"));
                cubicle.setStyle(attributes.getValue("style"));
                cubicle.setManufacturer(attributes.getValue("manufacturer"));
                cubicle.setWidth(attributes.getValue("width"));
                cubicle.setHeight(attributes.getValue("height"));
                cubicle.setDepth(attributes.getValue("depth"));
                cubicle.setColor(attributes.getValue("color"));
                cubicle.setShaftDirection(attributes.getValue("shaftDirection"));
                cubicle.setGridId(attributes.getValue("gridId"));
                cubicle.setObjectId(attributes.getValue("objectId"));
                // 封装到Cubicle信息集合
                cubicleMap.put(cubicle.getName(), cubicle);

                // 初始化列表细节
                functionAreaList = new ArrayList<>();
                deviceList = new ArrayList<>();
                coreList = new ArrayList<>();
                break;
            case "FunctionArea":
                functionArea = new FunctionArea();
                functionArea.setName(attributes.getValue("name"));
                functionArea.setDesc(attributes.getValue("desc"));
                // 初始化列表细节
                functionGroupList = new ArrayList<>();
                break;
            case "FunctionGroup":
                functionGroup = new FunctionGroup();
                functionGroup.setName(attributes.getValue("name"));
                functionGroup.setDesc(attributes.getValue("desc"));
                functionGroup.setType(attributes.getValue("type"));
                // 初始化列表细节
                interfaceList = new ArrayList<>();
                break;
            case "Interface":
                interfaceOne = new Interface();
                interfaceOne.setName(attributes.getValue("name"));
                interfaceOne.setDesc(attributes.getValue("desc"));
                interfaceOne.setClassName(attributes.getValue("class"));
                interfaceOne.setType(attributes.getValue("type"));
                // 初始化列表细节
                pointList = new ArrayList<>();
                break;
            case "Point":
                Point point = new Point();
                point.setType(attributes.getValue("type"));
                point.setDeviceName(attributes.getValue("device"));
                point.setSubDeviceName(attributes.getValue("subDevice"));
                point.setPinName(attributes.getValue("pin"));
                pointList.add(point);
                break;
            case "Device":
                device = new Device();
                device.setName(attributes.getValue("name"));
                device.setDesc(attributes.getValue("desc"));
                device.setLabel(attributes.getValue("label"));
                device.setIedName(attributes.getValue("iedName"));
                device.setGridId(attributes.getValue("gridId"));
                device.setObjectId(attributes.getValue("objectId"));
                device.setPartName(attributes.getValue("partName"));
                device.setType(attributes.getValue("type"));
                device.setManufacturer(attributes.getValue("manufacturer"));
                device.setClassName(attributes.getValue("class"));
                // 封装到Device信息集合
                String key = cubicle.getName() + "." + device.getName();
                deviceMap.put(key, device);


                // 初始化列表细节
                subDeviceList = new ArrayList<>();
                inDeviceList = new ArrayList<>();
                componentList = new ArrayList<>();
                inCoreList = new ArrayList<>();
                pinList = new ArrayList<>();
                break;
            case "SubDevice":
                // 子设备标记更改
                isSubDeviceFlag = true;
                subDevice = new SubDevice();
                subDevice.setName(attributes.getValue("name"));
                subDevice.setDesc(attributes.getValue("desc"));
                subDevice.setLabel(attributes.getValue("label"));
                subDevice.setGridId(attributes.getValue("gridId"));
                subDevice.setObjectId(attributes.getValue("objectId"));
                subDevice.setPartName(attributes.getValue("partName"));
                subDevice.setType(attributes.getValue("type"));
                subDevice.setManufacturer(attributes.getValue("manufacturer"));
                subDevice.setClassName(attributes.getValue("class"));
                // 初始化列表细节
                subInDeviceList = new ArrayList<>();
                subComponentList = new ArrayList<>();
                subInCoreList = new ArrayList<>();
                subPinList = new ArrayList<>();
                break;
            case "InCore":
                InCore inCore = new InCore();
                inCore.setName(attributes.getValue("name"));
                inCore.setDesc(attributes.getValue("desc"));
                inCore.setStartInPart(attributes.getValue("startInPart"));
                inCore.setStartComponent(attributes.getValue("startComponent"));
                inCore.setStartPinIndex(attributes.getValue("startPinIndex"));
                inCore.setEndInPart(attributes.getValue("endInPart"));
                inCore.setEndComponent(attributes.getValue("endComponent"));
                inCore.setEndPinIndex(attributes.getValue("endPinIndex"));
                if (isSubDeviceFlag) {
                    // 子设备
                    subInCoreList.add(inCore);
                } else {
                    inCoreList.add(inCore);
                }
                break;
            case "Pin":
                Pin pin = new Pin();
                pin.setName(attributes.getValue("name"));
                pin.setType(attributes.getValue("type"));
                pin.setDesc(attributes.getValue("desc"));
                pin.setSide(attributes.getValue("side"));
                if (isSubDeviceFlag) {
                    // 子设备
                    subPinList.add(pin);
                } else {
                    pinList.add(pin);
                }
                break;
            case "InDevice":
                // 设置内部器件标记
                isInDeviceFlag = true;
                InDevice tempInDevice = new InDevice();
                tempInDevice.setName(attributes.getValue("name"));
                tempInDevice.setDesc(attributes.getValue("desc"));
                tempInDevice.setType(attributes.getValue("type"));
                tempInDevice.setManufacturer(attributes.getValue("manufacturer"));
                tempInDevice.setClassName(attributes.getValue("class"));
                if (isSubDeviceFlag) {
                    subInDevice = new InDevice();
                    BeanUtil.copyProperties(tempInDevice, subInDevice);
                } else {
                    inDevice = new InDevice();
                    BeanUtil.copyProperties(tempInDevice, inDevice);
                }
                // 初始化列表细节
                inDeviceComponentList = new ArrayList<>();
                break;
            case "Component":
                Component tempComponent = new Component();
                tempComponent.setName(attributes.getValue("name"));
                tempComponent.setDesc(attributes.getValue("desc"));
                tempComponent.setGroup(attributes.getValue("group"));
                tempComponent.setType(attributes.getValue("type"));
                tempComponent.setIcdRef(attributes.getValue("icdRef"));
                tempComponent.setIcdPort(attributes.getValue("icdPort"));
                // 判定优先级：InDevice > SubDevice > Device
                if (isInDeviceFlag) {
                    inDeviceComponent = new Component();
                    BeanUtils.copyProperties(tempComponent, inDeviceComponent);
                    inDeviceComponentPinList = new ArrayList<>();
                } else if (isSubDeviceFlag) {
                    subComponent = new Component();
                    BeanUtils.copyProperties(tempComponent, subComponent);
                    subComponentPinList = new ArrayList<>();
                } else {
                    component = new Component();
                    BeanUtils.copyProperties(tempComponent, component);
                    componentPinList = new ArrayList<>();
                }
                break;
            case "ComponentPin":
                ComponentPin componentPin = new ComponentPin();
                componentPin.setPinIndex(attributes.getValue("pinIndex"));
                componentPin.setPinDesc(attributes.getValue("pinDesc"));
                // 判定优先级：InDevice > SubDevice > Device
                if (isInDeviceFlag) {
                    inDeviceComponentPinList.add(componentPin);
                } else if (isSubDeviceFlag) {
                    subComponentPinList.add(componentPin);
                } else {
                    componentPinList.add(componentPin);
                }
                break;
            case "Core":
                Core core = new Core();
                core.setName(attributes.getValue("name"));
                core.setDesc(attributes.getValue("desc"));
                core.setType(attributes.getValue("type"));
                core.setDesignation(attributes.getValue("designation"));
                core.setColor(attributes.getValue("color"));
                core.setStartDeviceName(attributes.getValue("startDeviceName"));
                core.setStartSubDeviceName(attributes.getValue("startSubDeviceName"));
                core.setStartPinName(attributes.getValue("startPinName"));
                core.setEndDeviceName(attributes.getValue("endDeviceName"));
                core.setEndSubDeviceName(attributes.getValue("endSubDeviceName"));
                core.setEndPinName(attributes.getValue("endPinName"));
                if (isCubicleFlag) {
                    coreList.add(core);
                } else {
                    cableCoreList.add(core);
                }
                break;
            case "Bay":
                bay = new Bay();
                bay.setName(attributes.getValue("name"));
                bay.setDesc(attributes.getValue("desc"));
                bay.setVoltageLevel(attributes.getValue("voltageLevel"));
                bay.setObjectId(attributes.getValue("objectId"));
                // 初始化列表
                deviceRefList = new ArrayList<>();
                cableList = new ArrayList<>();
                break;
            case "DeviceRef":
                DeviceRef deviceRef = new DeviceRef();
                deviceRef.setCubicleName(attributes.getValue("cubicleName"));
                deviceRef.setDeviceName(attributes.getValue("deviceName"));
                deviceRefList.add(deviceRef);
                break;
            case "Cable":
                cable = new Cable();
                cable.setName(attributes.getValue("name"));
                cable.setDesc(attributes.getValue("desc"));
                cable.setClassName(attributes.getValue("class"));
                cable.setType(attributes.getValue("type"));
                cable.setLength(attributes.getValue("length"));
                cable.setCoreNum(attributes.getValue("coreNum"));
                cable.setCrossSection(attributes.getValue("crossSection"));
                cable.setStartCubicleName(attributes.getValue("startCubicleName"));
                cable.setEndCubicleName(attributes.getValue("endCubicleName"));
                // 初始化列表
                cableCoreList = new ArrayList<>();
                break;
            default:
                break;


        }
    }

    /**
     * Receive notification of character data inside an element.
     *
     * <p>By default, do nothing.  Application writers may override this
     * method to take specific actions for each chunk of character data
     * (such as adding the data to a node or buffer, or printing it to
     * a file).</p>
     *
     * @param ch     The characters.
     * @param start  The start position in the character array.
     * @param length The number of characters to use from the
     *               character array.
     * @throws SAXException Any SAX exception, possibly
     *                      wrapping another exception.
     * @see ContentHandler#characters
     */
    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
        super.characters(ch, start, length);
    }

    /**
     * Receive notification of the end of an element.
     *
     * <p>By default, do nothing.  Application writers may override this
     * method in a subclass to take specific actions at the end of
     * each element (such as finalising a tree node or writing
     * output to a file).</p>
     *
     * @param uri       The Namespace URI, or the empty string if the
     *                  element has no Namespace URI or if Namespace
     *                  processing is not being performed.
     * @param localName The local name (without prefix), or the
     *                  empty string if Namespace processing is not being
     *                  performed.
     * @param qName     The qualified name (with prefix), or the
     *                  empty string if qualified names are not available.
     * @throws SAXException Any SAX exception, possibly
     *                      wrapping another exception.
     * @see ContentHandler#endElement
     */
    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {
        switch (qName) {
            case "SPD":
                spdData.setPartTemplateList(partTemplateList);
                spdData.setSubstation(substation);

                spdData.setCubicleMap(cubicleMap);
                spdData.setDeviceMap(deviceMap);
                log.info("SPD end");
                break;
            case "PartTemplates":
                log.info("PartTemplates end");
                break;
            case "PartTemplate":
                // 数据添加
                partTemplate.setComponentTemplateList(componentTemplateList);
                partTemplate.setInPartTemplateList(inPartTemplateList);
                partTemplate.setPinTemplateList(pinTemplateList);
                partTemplate.setInCoreTemplateList(inCoreTemplateList);
                partTemplateList.add(partTemplate);
                break;
            case "ComponentTemplate":
                // 数据添加
                componentTemplate.setComponentPinTemplateList(componentPinTemplateList);
                if (isInPartTemplateFlag) {
                    // 添加到InPartTemplate列表
                    inPartComponentTemplateList.add(componentTemplate);
                } else {
                    componentTemplateList.add(componentTemplate);
                }
                break;
            case "InPartTemplate":
                // 重置状态
                isInPartTemplateFlag = false;
                // 数据添加
                inPartTemplate.setComponentTemplateList(inPartComponentTemplateList);
                inPartTemplateList.add(inPartTemplate);
                break;
            case "Substation":
                substation.setRegionList(regionList);
                substation.setBayList(bayList);
                break;
            case "Region":
                region.setCubicleList(cubicleList);
                regionList.add(region);
                break;
            case "Cubicle":
                isCubicleFlag = false;
                cubicle.setFunctionAreaList(functionAreaList);
                cubicle.setDeviceList(deviceList);
                cubicle.setCoreList(coreList);
                cubicleList.add(cubicle);
                break;
            case "FunctionArea":
                functionArea.setFunctionGroupList(functionGroupList);
                functionAreaList.add(functionArea);
                break;
            case "FunctionGroup":
                functionGroup.setInterfaceList(interfaceList);
                functionGroupList.add(functionGroup);
                break;
            case "Interface":
                interfaceOne.setPointList(pointList);
                interfaceList.add(interfaceOne);
                break;
            case "Device":
                device.setSubDeviceList(subDeviceList);
                device.setInDeviceList(inDeviceList);
                device.setComponentList(componentList);
                device.setInCoreList(inCoreList);
                device.setPinList(pinList);
                deviceList.add(device);
                break;
            case "SubDevice":
                // 子设备标记更改
                isSubDeviceFlag = false;
                subDevice.setInDeviceList(subInDeviceList);
                subDevice.setComponentList(subComponentList);
                subDevice.setInCoreList(subInCoreList);
                subDevice.setPinList(subPinList);
                subDeviceList.add(subDevice);
                break;
            case "InDevice":
                // 设置内部器件标记
                isInDeviceFlag = false;
                if (isSubDeviceFlag) {
                    subInDevice.setComponentList(inDeviceComponentList);
                    subInDeviceList.add(subInDevice);
                } else {
                    inDevice.setComponentList(inDeviceComponentList);
                    inDeviceList.add(inDevice);
                }
                break;
            case "Component":
                if (isInDeviceFlag) {
                    inDeviceComponent.setComponentPinList(inDeviceComponentPinList);
                    inDeviceComponentList.add(inDeviceComponent);
                } else if (isSubDeviceFlag) {
                    subComponent.setComponentPinList(subComponentPinList);
                    subComponentList.add(subComponent);
                } else {
                    component.setComponentPinList(componentPinList);
                    componentList.add(component);
                }
                break;
            case "Bay":
                bay.setDeviceRefList(deviceRefList);
                bay.setCableList(cableList);
                bayList.add(bay);
                break;
            case "Cable":
                cable.setCoreList(cableCoreList);
                cableList.add(cable);
                break;
            default:
                break;
        }
    }

    /**
     * Receive notification of the end of the document.
     *
     * <p>By default, do nothing.  Application writers may override this
     * method in a subclass to take specific actions at the end
     * of a document (such as finalising a tree or closing an output
     * file).</p>
     *
     * @throws SAXException Any SAX exception, possibly
     *                      wrapping another exception.
     * @see ContentHandler#endDocument
     */
    @Override
    public void endDocument() throws SAXException {
        super.endDocument();
    }
}
